#include <aknutils.h>
#include <akndef.h>
#include "ContainerControl.h"
#include "BaseControl.h"

CContainerControl* CContainerControl::NewL(const TRect& aRect)
	{
	CContainerControl* self = CContainerControl::NewLC(aRect);
	CleanupStack::Pop(self);
	return self;
	}

CContainerControl* CContainerControl::NewLC(const TRect& aRect)
	{
	CContainerControl* self = new(ELeave) CContainerControl();
	CleanupStack::PushL(self);
	self->ConstructL(aRect);
	return self;
	}

CContainerControl::~CContainerControl()
	{
	Components().ResetAndDestroy();
	delete iBgContext;
	iBgContext = NULL;
	delete iScrollBarFrame;
	iScrollBarFrame = NULL;
	delete iBackGroundBitmap;
	iBackGroundBitmap = NULL;
	//iLog.CloseLog();
	//iLog.Close();
	}

CContainerControl::CContainerControl()
	{
	iBgContext = NULL;
	iScrollBarFrame = NULL;
	iFocusControl = NULL;
	iCurPos = 0;
	iMaxControlIndex = 0;
	iEnableSkin = ETrue;
	iBackGroundBitmap = NULL;
	iAutoLayout = ETrue;
	}

void CContainerControl::ConstructL(const TRect& aRect)
	{
	// No parent owner, so create an own window
    CreateWindowL();
    // Initialize component array
    InitComponentArrayL();

    // Creating Scroll Bars
    iScrollBarFrame = new ( ELeave ) CEikScrollBarFrame( this, NULL );
    iScrollBarFrame->CreateDoubleSpanScrollBarsL( ETrue, EFalse );
    iScrollBarFrame->SetTypeOfVScrollBar( CEikScrollBarFrame::EDoubleSpan );
    iScrollBarFrame->SetScrollBarVisibilityL( CEikScrollBarFrame::EOff,
    		CEikScrollBarFrame::EOff );
 
	iBgContext = CAknsBasicBackgroundControlContext::NewL(
		KAknsIIDQsnBgScreen,TRect(0,0,1,1), ETrue);
    SetRect(aRect);
    ActivateL();
	}

TKeyResponse CContainerControl::OfferKeyEventL(
		const TKeyEvent& aKeyEvent, TEventCode aType )
	{
	if ( iFocusControl != NULL
		&& iFocusControl->OfferKeyEventL( aKeyEvent, aType ) == EKeyWasConsumed )
		{
		return EKeyWasConsumed;
		}
	// Move focus
    switch ( aKeyEvent.iCode )
        {
        case EKeyUpArrow:
            {
            MoveFocusUpL();
            DrawNow(); // Draw components again
            return EKeyWasConsumed;
            }
        case EKeyDownArrow:
            {
            MoveFocusDownL();
            DrawNow(); // Draw components again
            return EKeyWasConsumed;
            }
        default:
            {
            return EKeyWasNotConsumed;
            }
        }
	}

void CContainerControl::HandlePointerEventL(const TPointerEvent& aPointerEvent)
	{
    CCoeControlArray::TCursor cursor = Components().Begin();
    CCoeControl* ctrl = NULL;
    while ((ctrl = cursor.Control<CCoeControl>()) != NULL)
        {
        if (ctrl->Rect().Contains(aPointerEvent.iPosition))
        	{
        	if (ctrl->IsFocused())
        		ctrl->HandlePointerEventL(aPointerEvent);
        	else
        		{
        		iFocusControl->SetFocus(EFalse);
        		iFocusControl = ctrl;
        		iFocusControl->SetFocus(ETrue);
        		}
        	DrawNow();
        	break;
        	}
        cursor.Next();
        }
	}

void CContainerControl::AddControlL(CCoeControl* aControl)
	{
	// NOTE: Transfer ownership of CCoeControl to CContainerControl
    // Add control into container control
    Components().AppendLC(aControl,iMaxControlIndex++);
    CleanupStack::Pop(aControl);

    // Focus first component
    if (Components().Count()== 1)
        {
        aControl->SetFocus(ETrue);
        iFocusControl = aControl;
        }
	}

TTypeUid::Ptr CContainerControl::MopSupplyObject(TTypeUid aId)
	{
	if (iEnableSkin && iBgContext)
		{
		return MAknsControlContext::SupplyMopObject(aId, iBgContext);
		}
	return CCoeControl::MopSupplyObject(aId);
	}

void CContainerControl::Draw(const TRect& aRect) const
	{
	CWindowGc& gc = SystemGc();
	gc.Clear(aRect);
	TRect rect = Rect();
	gc.SetBrushColor(KRgbRed);
	gc.DrawRect(aRect);
	// Redraw the background using the default skin
	if (iEnableSkin)
        {
        MAknsSkinInstance* skin = AknsUtils::SkinInstance();
        MAknsControlContext* cc = AknsDrawUtils::ControlContext( this );
        AknsDrawUtils::Background( skin, cc, this, gc, aRect );
        }
	else
        {
	    if (iBackGroundBitmap && iBackGroundBitmap->Bitmap())
             {
	         TRect bmpPieceRect(TPoint(0, 0), iBackGroundBitmap->SizeInPixels());
	        if (iBackGroundBitmap->MaskBitmap())
	             gc.DrawBitmapMasked(aRect,iBackGroundBitmap->Bitmap(),bmpPieceRect,iBackGroundBitmap->MaskBitmap(),EFalse);
	         else
	             gc.DrawBitmap(aRect, iBackGroundBitmap->Bitmap());
             }
	    else
	    {
	        gc.SetBrushStyle(CGraphicsContext::ESolidBrush);
	        gc.SetBrushColor(TRgb(255, 251, 242));
	        gc.SetPenColor(TRgb(255, 251, 242));
	        gc.DrawRect(aRect);
	    }
        }
	}

void CContainerControl::SizeChanged()
	{
	CCoeControl::SizeChanged();
	TRect rect;
	if (iEnableSkin)
        {
        if (iBgContext)
            {
            AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EScreen, rect);
            iBgContext->SetRect(rect);
            if ( &Window() )
                {
                iBgContext->SetParentPos(TPoint(0, 0) );
                }
            }
        }

    CCoeControlArray::TCursor cursor = Components().Begin();
    CCoeControl* ctrl = NULL;
    while ((ctrl = cursor.Control<CCoeControl>()) != NULL)
        {
        static_cast< CBaseControl* >(ctrl)->SizeChanged(Rect());
        cursor.Next();
        }
	UpdateControls();
	}

void CContainerControl::HandleResourceChange(TInt aType)
	{
	TRect rect;
	if (iEnableSkin && aType==KEikDynamicLayoutVariantSwitch)
		{
		AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EMainPane, rect);
		SetRect(rect);
		}
	CCoeControl::HandleResourceChange(aType);
	}

void CContainerControl::MoveFocusUpL()
	{
	CCoeControlArray::TCursor cursor = Components().Begin();
    CCoeControl* ctrl = NULL;
    CCoeControl* prevCtrl = NULL;
    while ((ctrl = cursor.Control<CCoeControl>()) != NULL)
        {
        if (ctrl->IsFocused())
            {
            if (prevCtrl)
                {
                if (((CBaseControl*)prevCtrl)->CanFocus())
                    {
                    TInt scroll = Min(Rect().Height() / 5,prevCtrl->Rect().Height());
                    if (IsInRect(prevCtrl)
                            && prevCtrl->Rect().iBr.iY - scroll > Rect().iTl.iY)
                        {
                        // Set focus to previous control
                        ctrl->SetFocus(EFalse);
                        prevCtrl->SetFocus(ETrue);
                        iFocusControl = prevCtrl;
                        iFocusedIndex--;
                        }
                    else
                        {
                        UpdateControls(scroll);
                        }
                    break;
                    }
                }
            else
                {
                if (ctrl->Rect().iTl.iY < Rect().iTl.iY)
                	{
                	TInt scroll = Min(Rect().Height() / 5,(Rect().iTl.iY - ctrl->Rect().iTl.iY + 2));
                	UpdateControls(scroll);
                	}
                break; // First control is already focused
                }
            }
        prevCtrl = ctrl;
        cursor.Next();
        }
	}

void CContainerControl::MoveFocusDownL()
	{
	CCoeControlArray::TCursor cursor = Components().Begin();
    CCoeControl* ctrl = NULL;
    CCoeControl* nextCtrl = NULL;
    while ((ctrl = cursor.Control<CCoeControl>()) != NULL)
        {
        if (ctrl && ctrl->IsFocused())
            {
            cursor.Next();
            nextCtrl = cursor.Control<CCoeControl>();
            if (nextCtrl)
                {
                if (((CBaseControl*)nextCtrl)->CanFocus())
                    {
                    TInt scroll = Min(Rect().Height() / 5, nextCtrl->Rect().Height());
                    if (IsInRect(nextCtrl)
                            && nextCtrl->Rect().iTl.iY + scroll < Rect().iBr.iY)
                        {
                        // Set focus to next control
                        ctrl->SetFocus(EFalse);
                        nextCtrl->SetFocus(ETrue);
                        iFocusControl = nextCtrl;
                        iFocusedIndex++;
                        }
                    else
                        {
                        if (nextCtrl->Rect().iBr.iY - Rect().iBr.iY > 0)
                            scroll = Min(scroll, nextCtrl->Rect().iBr.iY - Rect().iBr.iY + 2);
                        UpdateControls(-scroll);
                        }
                    break;
                    }
                }
            else
                {
                if (ctrl->Rect().iBr.iY > Rect().iBr.iY)
                	{
                	TInt scroll = Min(Rect().Height() / 5,(ctrl->Rect().iBr.iY - Rect().iBr.iY));
                	UpdateControls(-scroll);
                	}
                break; // Last control is already focused
                }
            }
        cursor.Next();
        }
	}

void CContainerControl::UpdateControls(TInt aOffset)
	{
	TPoint position;
    // Goes through all components of this container control
    CCoeControlArray::TCursor cursor = Components().Begin();
    CCoeControl* ctrl = cursor.Control<CCoeControl>();
    if (iAutoLayout)
    {
        if (ctrl)
            position = ctrl->Position();
        position.iY += aOffset;
        iCurPos -= aOffset;
    
        while ((ctrl = cursor.Control<CCoeControl>()) != NULL)
            {
            // Set position
            ctrl->SetPosition(position);
    
            if ( IsInRect(ctrl) )
                {
                ctrl->MakeVisible(ETrue);
                }
            else
                {
                ctrl->MakeVisible(EFalse);
                }
            // Calculate position
            position.iY += ctrl->Rect().Height();
            cursor.Next();
            }
    }
    else
    {
        iCurPos -= aOffset;
        while ((ctrl = cursor.Control<CCoeControl>()) != NULL)
            {
            position = ctrl->Position();
            position.iY += aOffset;
            // Set position
            ctrl->SetPosition(position);

            if ( IsInRect(ctrl) )
                {
                ctrl->MakeVisible(ETrue);
                }
            else
                {
                ctrl->MakeVisible(EFalse);
                }
            // Calculate position
            position.iY += ctrl->Rect().Height();
            cursor.Next();
            }
    }
    UpdateScrollBarFrameL();
	}

void CContainerControl::setEnableSkin(TBool aEnable)
    {
    iEnableSkin = aEnable;
    }

void CContainerControl::SetBackGroundBitmap(CImage* aImage)
    {
    delete iBackGroundBitmap;
    iBackGroundBitmap = NULL;
    iBackGroundBitmap = aImage;
    }

void CContainerControl::UpdateScrollBarFrameL()
	{
	TInt totalHeight = 0; // Height of the controls
    TInt height = 0; // This view height
    iShowScrollBar = EFalse;
    // Calculate components height
    CCoeControlArray::TCursor cursor = Components().Begin();
    CCoeControl* ctrl = NULL;
    while ((ctrl = cursor.Control<CCoeControl>()) != NULL)
        {
        totalHeight += ctrl->Size().iHeight;
        cursor.Next();
        }

    // This view height
    height = Rect().Height();

    // Set teh scrollbar visible if fields do not fit the screen
    if( totalHeight > height &&
         iScrollBarFrame->VScrollBarVisibility() == CEikScrollBarFrame::EOff)
        {
        iScrollBarFrame->SetScrollBarVisibilityL(CEikScrollBarFrame::EOff, // horizontal
                CEikScrollBarFrame::EOn); // vertical
        iShowScrollBar = ETrue;
        }
    // Hide the scrollbar if fields fit the screen
    else if ( totalHeight <= height &&
              iScrollBarFrame->VScrollBarVisibility() == CEikScrollBarFrame::EOn)
        {
        iScrollBarFrame->SetScrollBarVisibilityL(
                CEikScrollBarFrame::EOff, // horizontal
                CEikScrollBarFrame::EOff); // vertical
        }
    if (totalHeight <= height)
    	return ;
    // Update scroll bar position
    //iVDsSbarModel.SetScrollSpan(Components().Count());
    iVDsSbarModel.SetScrollSpan(totalHeight - height);
    TInt ws = Max(2,height * (totalHeight - height) / (totalHeight));
    iVDsSbarModel.SetWindowSize(ws);
    //iVDsSbarModel.SetFocusPosition(iFocusedIndex);
    iVDsSbarModel.SetFocusPosition(iCurPos);
    TEikScrollBarFrameLayout layout;
    layout.iTilingMode = TEikScrollBarFrameLayout::EInclusiveRectConstant;
    TRect rect = Rect();
    iScrollBarFrame->TileL(&iHDsSbarModel,&iVDsSbarModel,rect,rect,layout);
    iScrollBarFrame->SetVFocusPosToThumbPos(iVDsSbarModel.FocusPosition());
	}

TBool CContainerControl::IsInRect(CCoeControl* aCtrl)
	{
	if (aCtrl && (Rect().Contains(aCtrl->Position()) || Rect().iTl.iY < aCtrl->Rect().iBr.iY))
		return ETrue;
	else
		return EFalse;
	}
